const { execSync } = require('child_process');
const path = require('path');
const exampleEnvConfig = require('../env/example');
const dev = require('../env/dev.js');
const test = require('../env/test');
const prep = require('../env/prep');
const prod = require('../env/prod');

const ENV_PATH_MAP = {
  dev,
  test,
  prep,
  prod
};

function validateEnvConfig(example, config, targetEnvName) {
  const msg = s => `${targetEnvName}${s}`;
  if (typeof example !== typeof config) {
    return { result: false, message: msg('与示例类型不一致') };
  }
  if (!example || !config) {
    return { result: false, message: msg('或示例为空') };
  }
  const exampleKeys = Object.keys(example);
  const configKeys = Object.keys(config);

  while (exampleKeys.length) {
    const key = exampleKeys.pop();
    const index = configKeys.indexOf(key);
    if (index !== -1) {
      configKeys.splice(index, 1);
    } else {
      return { result: false, message: msg(`中的 ${key} 字段不存在`) };
    }
  }

  if (configKeys.length > 0) {
    return {
      result: false,
      message: msg(`中存在多余的字段 ${configKeys.join(',')}`)
    };
  }

  return { result: config };
}

function getNpmEnv(npmLifeCycle) {
  return npmLifeCycle.split(':');
}

function getNpmEnvTarget(npmLifeCycle) {
  const { 1: target } = getNpmEnv(npmLifeCycle);
  return target;
}

function getEnvConfig(npmLifeCycle) {
  const targetEnv = getNpmEnvTarget(npmLifeCycle);
  const envConfig = ENV_PATH_MAP[targetEnv] || ENV_PATH_MAP.dev;
  const configValidation = validateEnvConfig(
    exampleEnvConfig,
    envConfig,
    `${targetEnv} 环境文件`
  );
  if (configValidation.result) {
    return envConfig;
  }
  throw new Error(configValidation.message);
}

function stringObjectString(object) {
  return Object.keys(object).reduce((o, k) => {
    const value = object[k];
    let newValue = value;
    if (typeof value === 'string') {
      newValue = JSON.stringify(value);
    } else if (Array.isArray(value)) {
      newValue = value.map(stringObjectString);
    } else if (value && typeof value === 'object') {
      newValue = stringObjectString(value);
    }
    return { ...o, [k]: newValue };
  }, {});
}

function getGitBranch() {
  const branch = execSync('git rev-parse --abbrev-ref HEAD');
  return branch.toString().trim();
}

function getGitCommit() {
  const commit = execSync('git rev-parse HEAD');
  return commit.toString().trim();
}

const [targetAction, targetEnv] = getNpmEnv(process.env.npm_lifecycle_event);

const ENV = {
  TARGET_ACTION: targetAction,
  TARGET_ENV: targetEnv,
  GIT_BRANCH: getGitBranch(),
  GIT_COMMIT: getGitCommit(),
  ...getEnvConfig(process.env.npm_lifecycle_event)
};

Object.keys(ENV).forEach(key => {
  if (process.env[key] == null) {
    process.env[key] = ENV[key];
  }
});

module.exports = stringObjectString(ENV);
